/*
 * Copyright 2006-2023 ahtelit.com, All Rights Reserved.
 */

package com.telit.common.util;

import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;


/**
 * MD5 加解密工具类。
 */
@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class Md5Util {

    private static final char[] hexDigits = {
            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
    };

    private static MessageDigest messageDigest = null;

    static {
        try {
            messageDigest = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException ex) {
            log.error("{}", "Md5Util static init failed", ex);
        }
    }

    /**
     * Gets md5 hash code for a string.
     *
     * @param input the original string
     *
     * @return the md5 string represented in hexadecimal
     */
    public static String stringMD5(String input) {
        byte[] inputByteArray = input.getBytes();
        messageDigest.update(inputByteArray);

        return byteArrayToHex(messageDigest.digest());
    }

    /**
     * Gets a 16 bytes md5 hash code for a string.
     *
     * @param input the original string
     *
     * @return the md5 string represented in hexadecimal
     */
    public static String stringMD5_16(String input) {
        return stringMD5(input).substring(8, 24);
    }

    /**
     * Gets md5 hash code for a file.
     *
     * @param file the file
     *
     * @return the md5 string
     * @throws IOException if file i/o error
     */
    public static String fileMD5(File file) throws IOException {
        try (InputStream fis = new FileInputStream(file)) {
            byte[] buffer = new byte[1024];
            int numRead = 0;

            while ((numRead = fis.read(buffer)) > 0) {
                messageDigest.update(buffer, 0, numRead);
            }
        }

        return byteArrayToHex(messageDigest.digest());
    }

    // ----

    private static String byteArrayToHex(byte[] byteArray) {
        char[] resultCharArray = new char[byteArray.length * 2];
        int index = 0;

        for (byte b : byteArray) {
            resultCharArray[index++] = hexDigits[b >>> 4 & 0xf];
            resultCharArray[index++] = hexDigits[b & 0xf];
        }

        return new String(resultCharArray);
    }

}
